package pt.iscte.dcti.pa.model;

import java.util.List;
import java.util.ArrayList;

import utils.Common;
import utils.SingletonRmiWrapper;

public class Mathematician {

	// ATRIBUTOS
	private RemoteCalculator[] remoteCalculators;
	private String expression;
	private List<String> matches;

	private static class RemoteCalculator extends Thread {
		public final static int THREADPASS = 0;
		public final static int THREADFAIL = 1;
		
		private String match;
		public String getMatch() {
			return match;
		}

		private int _status;
		public int getStatus() {
			return _status;
		}

		private SingletonRmiWrapper rmiWrapper;
		
		private String result;
		public String getResult() {
			return result;
		}

		public RemoteCalculator(String _match) {
			_status = THREADFAIL;
			match = _match;
			rmiWrapper = SingletonRmiWrapper.getWrapper();
		}

		public void run() {			
			result = rmiWrapper.getPrecedentOperationResult(match);			
			_status = THREADPASS;
		}
	}

	// CONSTRUCTORS
	public Mathematician(final String _expression) {
		
		this.expression = _expression;
		matches = Common.getMatches("\\d+([\\*/]\\d+)+", expression);
		remoteCalculators = new RemoteCalculator[matches.size()];
		
	}

	// PUBLIC METHODS
	public String doMath() {

		int res = 0, i = 0;

		for (String match : matches) {
			remoteCalculators[i] = new RemoteCalculator(match);
			remoteCalculators[i].start();
			i++;
		}
		
		for (RemoteCalculator calc : remoteCalculators) {
			try {
				calc.join();
			} catch (InterruptedException e) {
				System.out.println("Join interrupted");
			}
		}
		
		for (RemoteCalculator calc : remoteCalculators) {
			if (calc.getStatus() != RemoteCalculator.THREADPASS || calc.getResult() == null) {
				System.out.println("Unexpected Thread Status");
				return null;
			}
			
			this.expression = this.expression.replace(calc.getMatch(), calc.getResult());
		}
		
		matches = Common.getMatches("(\\-|\\+)?\\d+", expression); // Ja nao ha produtos ou divisoes
		
		for (String part : matches) {
			res += Integer.parseInt(part);
		}

		return Integer.toString(res);
	}

	// PRIVATE METHODS
	
}
